home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-12-10 | 10.7 KB | 484 lines | [TEXT/KAHL] |
- /*
- ** CTCPDriver.cp
- **
- ** TurboTCP support library
- ** TCP driver interface class
- **
- ** Copyright © 1993, FrostByte Design / Eric Scouten
- **
- */
-
-
- #define CTCPDriverNoGlobal // don’t redefine global vars
- #include "CTCPDriver.h"
-
- #ifndef TurboTCPHeaders
- #include <CApplication.h>
- #include <CBartender.h>
- #include <GetMyIPAddr.h>
- #include <cast.h>
- #endif
-
- #include <CDLOGDirector.h>
-
- #include "CTCPApplication.h"
- #include "CTCPAsyncCall.h"
- #include "CTCPStream.h"
- #include "CTCPResolverCall.h"
-
-
- // resource definitions
-
- #define DLOG_TCPDelayedQuit 23010
-
-
- // define global reference to the TCP driver object
-
- extern CApplication *gApplication;
- extern CBartender *gBartender;
- CTCPDriver *gTCPDriver; // not a class variable since it’s used
- // so frequently throughout the application
-
-
- // —— contruction/destruction ——
-
- /*______________________________________________________________________
- **
- ** ITCPDriver
- **
- ** Clear the TCP driver object. Check to see if MacTCP is open. Optionally, opens TCP
- ** resolver.
- **
- ** doOpenResolver (Boolean): TRUE to open TCP resolver as well
- **
- */
-
- void CTCPDriver::ITCPDriver (Boolean doOpenResolver)
-
- {
-
- // driver object must be locked, since it may be accessed during interupts
-
- MoveHHi((Handle) this);
- this->Lock(TRUE);
-
-
- // clear variables
-
- hasMacTCP = FALSE;
- hasResolver = FALSE;
- myTCPRefNum = 0;
- myIPAddress = 0L;
- gTCPDriver = this;
- activeStreamList = NULL;
- activeResolverList = NULL;
-
-
- // clear asynch processing queue
-
- asyncQueue.qFlags = 0;
- asyncQueue.qHead = NULL;
- asyncQueue.qTail = NULL;
-
-
- // create the active TCP/DNR call lists
-
- activeStreamList = new (CCluster);
- activeStreamList->ICluster();
-
- activeResolverList = new (CCluster);
- activeResolverList->ICluster();
-
-
- // see if TCP & DNR are available
-
- CheckTCPDriver();
- if (doOpenResolver)
- CheckResolver();
-
- }
-
-
- /*______________________________________________________________________
- **
- ** Dispose
- **
- ** Dispose of this object and any lingering TCP async call objects or TCP stream objects.
- ** It is CRITICAL that any lingering TCP streams be closed, released, and disposed;
- ** otherwise MacTCP is *guaranteed* to crash the machine when the next app launches.
- ** If the resolver is open, wait until all resolver queries have been cancelled.
- **
- ** If at least one second elapses between the start of this routine and the end, flash a
- ** dialog box to indicate the reason for the delay.
- **
- */
-
- void CTCPDriver::Dispose (void)
-
- {
- register long i;
- CTCPStream *theStream;
- unsigned long startTickCount;
- unsigned long theTime;
- CDLOGDirector *theDialog = NULL;
-
-
- // cancel outstanding DNR calls & close resolver
-
- if (hasResolver)
- CTCPResolverCall::CloseResolver();
-
-
- // kill any lingering streams
-
- if (activeStreamList) {
- for (i = 0; i < activeStreamList->numItems; i++) {
- theStream = (CTCPStream*) (*(activeStreamList->items))[i];
- theStream->PostponeDispose();
- }
- }
-
-
- // wait for TCP to be done with everything
-
- GetDateTime(&startTickCount);
- gBartender->DisableMenuBar(); // disable all menus
-
- while (!activeStreamList->IsEmpty()) {
-
-
- // do a private event loop & toss up a dialog if it takes more than 2 seconds
-
- GetDateTime(&theTime);
- if ((theDialog == NULL) && (theTime - startTickCount >= 2)) {
- theDialog = new (CDLOGDirector);
- theDialog->IDLOGDirector(DLOG_TCPDelayedQuit, gApplication);
- theDialog->BeginDialog();
- }
-
-
- // wait for TCP completions & terminations
-
- gApplication->Process1Event();
-
- }
-
-
- // get rid of dialog box (if there was one)
-
- ForgetObject(theDialog);
-
-
- // dispose all the objects
-
- ForgetObject(activeStreamList);
- ForgetObject(activeResolverList);
- CObject::Dispose();
-
- }
-
-
- // —— event handling ——
-
- /*______________________________________________________________________
- **
- ** ProcessNetEvents
- **
- ** Respond to all delayed TCP notifications, completions, disposals. This routine should be
- ** hooked into the application’s event loop or some very frequently called routine.
- **
- */
-
- void CTCPDriver::ProcessNetEvents (void)
-
- {
- CObject *theAsyncObject;
- TurboTCPQElemPtr theAsyncEntry;
- CTCPAsyncCall *theAsyncCall;
- CTCPResolverCall *theResolverCall;
- CTCPStream *theStream;
-
-
- // respond to all the events in the TCP asynchronous events queue, if there are any
-
- while (asyncQueue.qHead) {
-
- // figure out what object caused the notification
-
- theAsyncEntry = (TurboTCPQElemPtr) asyncQueue.qHead;
- theAsyncObject = theAsyncEntry->qSelfLink;
-
-
- // remove it from the queue (just in case the event processing fails)
-
- Dequeue((QElemPtr) theAsyncEntry, &asyncQueue);
-
-
- // process the event
-
- switch (theAsyncEntry->qType) {
- case asyncCall:
- theAsyncCall = CheckedCast(theAsyncObject, CTCPAsyncCall);
- if (theAsyncCall)
- theAsyncCall ->ProcessCompletion();
- break;
- case resolverCall:
- theResolverCall = CheckedCast(theAsyncObject, CTCPResolverCall);
- if (theResolverCall)
- theResolverCall->ProcessNotify();
- break;
- case notifyStream:
- theStream = CheckedCast(theAsyncObject, CTCPStream);
- if (theStream)
- theStream->ProcessNotify();
- break;
- case disposeStream:
- theStream = CheckedCast(theAsyncObject, CTCPStream);
- if (theStream)
- theStream->Dispose();
- break;
-
- } // switch
- } // while
-
- }
-
-
- // —— ensure that TCP/DNR are present ——
-
- /*______________________________________________________________________
- **
- ** CheckTCPDriver
- **
- ** Check to see if the MacTCP driver is present. Should be done before opening each new
- ** connection (built into CTCPStream). If TCP driver is present, updates the current IP address.
- **
- ** return (Boolean): TRUE if MacTCP driver is present
- **
- */
-
- Boolean CTCPDriver::CheckTCPDriver (void)
-
- {
- ParamBlockRec theParamBlock;
- unsigned char theName[6] = "\p.IPP"; // MacTCP driver name
-
-
- // if TCP not already confirmed, look for it
-
- if (!hasMacTCP) {
- theParamBlock.ioParam.ioNamePtr = (StringPtr) &theName;
- theParamBlock.ioParam.ioPermssn = fsCurPerm;
- if ((short) PBOpenSync(&theParamBlock) == 0) {
- myTCPRefNum = theParamBlock.ioParam.ioRefNum;
- hasMacTCP = TRUE;
- }
- }
-
-
- /*
- ** If TCP driver available, get the IP address. This is done *each* time a new stream
- ** is created because the address might have changed. (This could happen on a machine
- ** connected by modem & SLIP, if the user hangs up the modem and re-dials the
- ** SLIP server without quitting the program.)
- */
-
- FetchIPAddr();
- return (hasMacTCP);
-
- }
-
-
- /*______________________________________________________________________
- **
- ** CheckResolver
- **
- ** Check to see if the MacTCP DNR code segment is available. If it isn’t, use the OpenResolver
- ** call to make it available.
- **
- ** return (Boolean): TRUE if TCP resovler is present
- **
- */
-
- Boolean CTCPDriver::CheckResolver (void)
-
- {
-
- TRY {
- CTCPResolverCall::OpenResolver();
- hasResolver = TRUE;
- }
- CATCH {
- hasResolver = FALSE;
- NO_PROPAGATE;
- }
- ENDTRY;
- return (hasResolver);
-
- }
-
-
- // —— get TCP driver numbers ——
-
- /*______________________________________________________________________
- **
- ** GetTCPRefNum
- **
- ** Returns the Device Manager reference number for MacTCP, if available. Fails with
- ** “noTCPError” error if not available.
- **
- ** return (short): MacTCP driver refnum
- **
- */
-
- short CTCPDriver::GetTCPRefNum (void)
-
- {
- if (!hasMacTCP)
- FailOSErr(noTCPError);
- return (myTCPRefNum);
- }
-
-
- /*______________________________________________________________________
- **
- ** GetIPAddr
- **
- ** Returns the current local IP address, if available. Fails with “noTCPError” error if
- ** MacTCP is not installed.
- **
- ** return (ip_addr): current IP address
- **
- */
-
- ip_addr CTCPDriver::GetIPAddr (void)
-
- {
- if (!hasMacTCP)
- FailOSErr(noTCPError);
- return (myIPAddress);
- }
-
-
- /*______________________________________________________________________
- **
- ** FetchIPAddr (protected method)
- **
- ** Retrieve the local host’s IP address. Does nothing if MacTCP is not available. Stores the
- ** new address in the local field myIPAddress, which can be retrieved with the
- ** GetIPAddr() method.
- **
- */
-
- void CTCPDriver::FetchIPAddr (void)
-
- {
- struct GetAddrParamBlock theIPParamBlock;
-
- myIPAddress = 0L;
-
- if (hasMacTCP) {
- theIPParamBlock.csCode = ipctlGetAddr;
- theIPParamBlock.ioCRefNum = myTCPRefNum;
- PBControlSync((ParmBlkPtr) &theIPParamBlock);
- if (theIPParamBlock.ioResult == noErr)
- myIPAddress = theIPParamBlock.ourAddress;
- }
- }
-
-
- // —— postpone processing of interrupt-level notification ——
-
- /*______________________________________________________________________
- **
- ** RegisterActiveStream
- **
- ** Add a TCP stream to the list of active TCP streams. The driver object uses this information
- ** to ensure that all streams are closed and terminated before the application quits.
- **
- ** theStream (CTCPStream *): the stream to register
- **
- */
-
- void CTCPDriver::RegisterActiveStream (CTCPStream *theStream)
-
- {
- activeStreamList->Add(theStream);
- }
-
-
- /*______________________________________________________________________
- **
- ** RegisterActiveResolver
- **
- ** Add a DNR resolver call to the list of active TCP streams. The driver object uses this
- ** information to ensure that all resolver calls are closed and terminated before the
- ** application quits.
- **
- ** theResolver (CTCPResolverCall *): the resolver call to register
- **
- */
-
- void CTCPDriver::RegisterActiveResolver (CTCPResolverCall *theResolver)
-
- {
- if (CheckResolverLimit()) // disallow 9th DNR call
- FailOSErr(resolverBusy);
- activeResolverList->Add(theResolver);
- }
-
-
- /*______________________________________________________________________
- **
- ** RemoveActiveStream
- **
- ** Remove a TCP stream from the list of active TCP streams. This message indicates that
- ** MacTCP is no longer dependent on the memory structure for the stream.
- **
- ** theStream (CTCPStream *): the stream to register
- **
- */
-
- void CTCPDriver::RemoveActiveStream (CTCPStream *theStream)
-
- {
- if (activeStreamList) // just in case this is called during shutdown
- activeStreamList->Remove(theStream);
- }
-
-
- /*______________________________________________________________________
- **
- ** RemoveActiveResolver
- **
- ** Remove a DNR resolver call from the list of active calls. This message indicates that
- ** the MacTCP DNR is no longer dependent on the memory structure for the call.
- **
- ** theResolver (CTCPResolverCall *): the resolver call to register
- **
- */
-
- void CTCPDriver::RemoveActiveResolver (CTCPResolverCall *theResolver)
-
- {
- if (activeResolverList) // just in case this is called during shutdown
- activeResolverList->Remove(theResolver);
- }
-
-
- /*______________________________________________________________________
- **
- ** CheckResolverLimit
- **
- ** Test to see if the DNR is at its capacity for active calls (currently 8).
- **
- ** return (Boolean): TRUE if no more DNR calls may be issued now
- **
- */
-
- Boolean CTCPDriver::CheckResolverLimit (void)
-
- {
- return ((activeResolverList->numItems) >= maxResolverCalls);
- }
-